package cau.se.project;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cau.se.project.data.CLSXTreeModel;
import cau.se.project.data.method.GroupControl;
import cau.se.project.data.method.RowControl;
import cau.se.project.method.CLSXControl;
import cau.se.project.method.DSMControl;
import cau.se.project.method.FileControl;

public class CLSXFile implements FileControl {

	private DSMControl dsm = null;
	private File currentFile = null;

	public CLSXFile(DSMControl dsm)
	{
		this.dsm = dsm;
	}

	@Override
	public void newFile() {
		currentFile = null;
	}

	@Override
	public CLSXControl open(File file) throws Exception
	{
		DocumentBuilder builder;
		System.out.println("open CLSXFile " + file.getAbsolutePath());
		
		if(dsm == null)
			throw new Exception("no dsm opened!");
		
		// tree
		CLSXControl clsx = new CLSXTreeModel();
		
		// xml파싱 과정
		builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document document = builder.parse(file);
		
		// root node
		Node element = document.getDocumentElement().getElementsByTagName("group").item(0);
		if(element == null)
			throw new Exception("no root group!");
		
		// root's name
		GroupControl root = (GroupControl) clsx.getRoot();
		root.setName(((Element)element).getAttribute("name"));
		
		// make tree
		addChildren(clsx, root, element);
		
		// 나머지 clsx에 등록 안된 row은 추가함
		for(int i=0; i<dsm.getSize(); i++) {
			clsx.addRow(dsm.getRow(i));
		}
		
		// dsm 갱신
		this.dsm = clsx.getDSM();

		currentFile = file;
		return clsx;
	}

	/**
	 * xml파싱 결과를 토대로 트리를 만들어 나간다<br/>
	 * group 밑에 node의 child가 들어간다 
	 * @param clsx tree
	 * @param group	tree상의 group
	 * @param node	xml상의 group
	 * @throws Exception
	 */
	private void addChildren(CLSXControl clsx, GroupControl group, Node node) throws Exception
	{
		NodeList childList = node.getChildNodes();
		for(int i=0; i<childList.getLength(); i++) {
			Node child = childList.item(i);
			if(child.getNodeType() != Node.ELEMENT_NODE)
				continue;

			String nodeName = ((Element)child).getAttribute("name");
			//System.out.println("node " + n.getNodeName() + " found, name: " + nodeName);

			if(child.getNodeName().equals("group")) {
				// group
				GroupControl g = clsx.makeGroup(nodeName);
				group.addGroupMember(g);
				
				// insert group's item
				System.out.println("group " + nodeName + " start");
				addChildren(clsx, g, child);
				System.out.println("group " + nodeName + "'s end");
			}
			else {
				// item
				// dsm에 있는 row만 넣는다
				RowControl row = dsm.findRowByName(nodeName);
				if(row != null) {
					System.out.println("insert " + row.getName());
					// 원래 dsm에서 삭제
					dsm.removeRow(row);
					
					// 새로운 dsm에 삽입
					clsx.getDSM().insertRow(row, null);
					group.addGroupMember(row);
				}
				else {
					System.out.println("cannot find " + nodeName);
				}
			}
		}
	}

	@Override
	public void save(CLSXControl clsx) throws Exception
	{
		System.out.println("save to " + currentFile.getAbsolutePath());
		BufferedWriter writer = new BufferedWriter(new FileWriter(this.currentFile));

		writer.write("<cluster>" + "\r\n");
		writeSave(writer, ((RowControl)clsx.getRoot()));			
		writer.write("</cluster>" + "\r\n");

		writer.close();
	}

	private void writeSave(BufferedWriter writer, RowControl rowControl) throws Exception {
		// TODO alksdflkajsdlkfjk
		if ( rowControl.getParent() == null && rowControl.isLeaf() ) {
			rowControl = (RowControl)rowControl.getChildAt(0);
			int i = rowControl.getChildCount();
			writer.write("<item name=\"" + rowControl.getName() + "\">\n");
			for ( i = 0; i < rowControl.getChildCount(); i++ ) {
				writeSave(writer, (RowControl)rowControl.getChildAt(i));
			}
			writer.write("</item>" + "\n");
		} else if ( rowControl.getParent() == null ) {
			int i = rowControl.getChildCount();
			if ( i == 0 ) {
				writer.write("<group name=\"" + rowControl.getName() + "\">\n");
			} else {
				writer.write("<group name=\"" + rowControl.getName() + "\">\n");
				for ( i = 0; i < rowControl.getChildCount(); i++ ) {
					writeSave(writer, (RowControl)rowControl.getChildAt(i));
				}
				writer.write("</group>" + "\n");
			}
		} else if ( rowControl.isLeaf() ) {
			writer.write("<item name=\"");
			writer.write(rowControl.getName());
			writer.write("\" />" + "\n");
		} else {
			int i = rowControl.getChildCount();
			if ( i == 0 ) {
				writer.write("<group name=\"" + rowControl.getName() + "\">\n");
			} else {
				writer.write("<group name=\"" + rowControl.getName() + "\">\n");
				for ( i = 0; i < rowControl.getChildCount(); i++ ) {
					writeSave(writer, (RowControl)rowControl.getChildAt(i));
				}
				writer.write("</group>" + "\n");
			}
		}
	}

	@Override
	public void saveAs(CLSXControl clsx, File file) throws Exception
	{
		this.currentFile = file;
		this.save(clsx);
	}

	@Override
	public File getCurrentFile() {
		return currentFile;
	}

}
